#------------------------------------------------------------------------------
# Include source and build directories
#------------------------------------------------------------------------------
set(MERCURY_BUILD_INCLUDE_DEPENDENCIES
  ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_CURRENT_BINARY_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra
)

#------------------------------------------------------------------------------
# Internal dependencies (exported libs)
#------------------------------------------------------------------------------
# UTIL
set(MERCURY_UTIL_INSTALL_BIN_DIR ${MERCURY_INSTALL_BIN_DIR})
set(MERCURY_UTIL_INSTALL_LIB_DIR ${MERCURY_INSTALL_LIB_DIR})
set(MERCURY_UTIL_INSTALL_INCLUDE_DIR ${MERCURY_INSTALL_INCLUDE_DIR})
set(MERCURY_UTIL_INSTALL_DATA_DIR ${MERCURY_INSTALL_DATA_DIR})
set(MERCURY_UTIL_EXPORTED_TARGETS ${MERCURY_EXPORTED_TARGETS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/util)
set(MERCURY_INT_PKG_EXPORTED_LIBS ${MERCURY_INT_PKG_EXPORTED_LIBS} mercury_util)

# Multi progress
option(HG_ALLOW_MULTI_PROGRESS "Allow concurrent progress on single context." ON)
if(HG_ALLOW_MULTI_PROGRESS)
  set(HG_HAS_MULTI_PROGRESS 1)
endif()
mark_as_advanced(HG_ALLOW_MULTI_PROGRESS)

# NA
set(NA_INSTALL_BIN_DIR ${MERCURY_INSTALL_BIN_DIR})
set(NA_INSTALL_LIB_DIR ${MERCURY_INSTALL_LIB_DIR})
set(NA_INSTALL_INCLUDE_DIR ${MERCURY_INSTALL_INCLUDE_DIR})
set(NA_INSTALL_DATA_DIR ${MERCURY_INSTALL_DATA_DIR})
set(NA_EXPORTED_TARGETS ${MERCURY_EXPORTED_TARGETS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/na)
set(MERCURY_INT_PKG_EXPORTED_LIBS ${MERCURY_INT_PKG_EXPORTED_LIBS} na)

#------------------------------------------------------------------------------
# External dependencies
#------------------------------------------------------------------------------
# Boost (for preprocessor macros)
option(MERCURY_USE_BOOST_PP "Use BOOST preprocessor macros." OFF)
if(MERCURY_USE_BOOST_PP)
  option(MERCURY_USE_SYSTEM_BOOST "Use system-installed Boost libraries." OFF)
  if(MERCURY_USE_SYSTEM_BOOST)
    find_package(Boost 1.41.0 REQUIRED)
    message(STATUS "Boost include directory: ${Boost_INCLUDE_DIRS}")
    set(HG_HAS_BOOST 1)
    set(MERCURY_EXT_INCLUDE_DEPENDENCIES
      ${MERCURY_EXT_INCLUDE_DEPENDENCIES}
      ${Boost_INCLUDE_DIRS}
    )
  else()
    set(HG_HAS_BOOST 1)
    set(MERCURY_BUILD_INCLUDE_DEPENDENCIES
      ${MERCURY_BUILD_INCLUDE_DEPENDENCIES}
      ${CMAKE_CURRENT_SOURCE_DIR}/boost
    )
  endif()
endif()

# MChecksum
option(MERCURY_USE_CHECKSUMS "Checksum transfers of RPC arguments." OFF)
if(MERCURY_USE_CHECKSUMS)
  set(HG_HAS_CHECKSUMS 1)
  option(MERCURY_USE_SYSTEM_MCHECKSUM "Use system-installed MChecksum." OFF)
  if(MERCURY_USE_SYSTEM_MCHECKSUM)
    find_package(mchecksum REQUIRED)
    set(MERCURY_INT_PKG_DEPENDENCIES
      ${MERCURY_INT_PKG_DEPENDENCIES}
      mchecksum
    )
  else()
    set(MCHECKSUM_EXTERNALLY_CONFIGURED 1)
    set(MCHECKSUM_INSTALL_BIN_DIR ${MERCURY_INSTALL_BIN_DIR})
    set(MCHECKSUM_INSTALL_LIB_DIR ${MERCURY_INSTALL_LIB_DIR})
    set(MCHECKSUM_INSTALL_INCLUDE_DIR ${MERCURY_INSTALL_INCLUDE_DIR})
    set(MCHECKSUM_INSTALL_DATA_DIR ${MERCURY_INSTALL_DATA_DIR})
    # TODO might need to fix MCHECKSUM_INSTALL_INCLUDE_INTERFACE from here
    set(MCHECKSUM_EXTERNAL_EXPORTED_TARGETS ${MERCURY_EXPORTED_TARGETS})
    add_subdirectory(mchecksum)
    include(${MCHECKSUM_BINARY_DIR}/mchecksum-config.cmake)
    set(MERCURY_INT_PKG_EXPORTED_LIBS mchecksum ${MERCURY_INT_PKG_EXPORTED_LIBS})
  endif()
endif()

# XDR
option(MERCURY_USE_XDR "Use XDR for generic encoding." OFF)
if(MERCURY_USE_XDR)
  # Detect <rpc/xdr.h>
  check_include_files("rpc/xdr.h" HG_HAS_RPC_XDR_H)

  # <rpc/xdr.h> is not present in recent distributions, look for tirpc instead
  if(NOT HG_HAS_RPC_XDR_H AND NOT APPLE AND NOT WIN32)
    find_package(TIRPC REQUIRED)
    message(STATUS "TIRPC include directory: ${TIRPC_INCLUDE_DIRS}")
    set(MERCURY_EXT_INCLUDE_DEPENDENCIES
      ${MERCURY_EXT_INCLUDE_DEPENDENCIES}
      ${TIRPC_INCLUDE_DIRS}
    )
    set(MERCURY_EXT_LIB_DEPENDENCIES
      ${MERCURY_EXT_LIB_DEPENDENCIES}
      ${TIRPC_LIBRARIES}
    )
  endif()
  set(HG_HAS_XDR 1)
endif()

# For htonl etc
if(WIN32)
  set(MERCURY_INT_LIB_DEPENDENCIES ${MERCURY_INT_LIB_DEPENDENCIES} ws2_32)
endif(WIN32)

# Define internal pkg dependencies
set(MERCURY_INT_PKG_DEPENDENCIES ${MERCURY_INT_PKG_DEPENDENCIES}
    ${MERCURY_INT_PKG_EXPORTED_LIBS})

#------------------------------------------------------------------------------
# Configure module header files
#------------------------------------------------------------------------------
# Set unique vars used in the autogenerated config file (symbol import/export)
configure_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_config.h.in
  ${CMAKE_CURRENT_BINARY_DIR}/mercury_config.h
)

#------------------------------------------------------------------------------
# Set sources
#------------------------------------------------------------------------------
set(MERCURY_SRCS
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury.c
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_bulk.c
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_core.c
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_core_header.c
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_header.c
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc.c
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc_bulk.c
  ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_string.c
  ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_string_object.c
)

#------------------------------------------------------------------------------
# Specify project public header files to be installed
#------------------------------------------------------------------------------
set(MERCURY_PUBLIC_HEADERS
  ${CMAKE_CURRENT_BINARY_DIR}/mercury_config.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_bulk.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_core.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_core_header.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_core_types.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_header.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_macros.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc_bulk.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_types.h
  ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_string.h
  ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_string_object.h
)

#------------------------------------------------------------------------------
# Specify project private header files
#------------------------------------------------------------------------------
set(MERCURY_PRIVATE_HEADERS
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_bulk_proc.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_error.h
  ${CMAKE_CURRENT_SOURCE_DIR}/mercury_private.h
)

#------------------------------------------------------------------------------
# Libraries
#------------------------------------------------------------------------------

# Clean up system include path first
mercury_clean_include_path(MERCURY_INT_INCLUDE_DEPENDENCIES)
mercury_clean_include_path(MERCURY_EXT_INCLUDE_DEPENDENCIES)

# MERCURY
add_library(mercury ${MERCURY_SRCS}
  ${MERCURY_PRIVATE_HEADERS} ${MERCURY_PUBLIC_HEADERS}
)
target_include_directories(mercury
  PUBLIC  "$<BUILD_INTERFACE:${MERCURY_BUILD_INCLUDE_DEPENDENCIES}>"
          $<INSTALL_INTERFACE:${MERCURY_INSTALL_INCLUDE_INTERFACE}>
          $<TARGET_PROPERTY:mercury_util,INTERFACE_INCLUDE_DIRECTORIES>
          $<TARGET_PROPERTY:na,INTERFACE_INCLUDE_DIRECTORIES>
)
target_include_directories(mercury
  SYSTEM PUBLIC   ${MERCURY_EXT_INCLUDE_DEPENDENCIES}
         PRIVATE  ${MERCURY_INT_INCLUDE_DEPENDENCIES}
)
target_link_libraries(mercury
  PUBLIC  ${MERCURY_EXT_LIB_DEPENDENCIES}
  PRIVATE ${MERCURY_INT_LIB_DEPENDENCIES} ${MERCURY_INT_PKG_DEPENDENCIES}
)
mercury_set_lib_options(mercury "mercury" ${MERCURY_LIBTYPE} ${PROJECT_NAME})
if(MERCURY_ENABLE_COVERAGE)
  set_coverage_flags(mercury)
endif()
set_target_properties(mercury PROPERTIES
  PUBLIC_HEADER "${MERCURY_PUBLIC_HEADERS}"
)

set(MERCURY_EXPORTED_LIBS mercury ${MERCURY_INT_PKG_EXPORTED_LIBS})

#-----------------------------------------------------------------------------
# Add file(s) to CMake Install
#-----------------------------------------------------------------------------
if(MERCURY_USE_BOOST_PP AND NOT MERCURY_USE_SYSTEM_BOOST)
  install(
    DIRECTORY
      boost
    DESTINATION
      ${MERCURY_INSTALL_INCLUDE_DIR}
    COMPONENT
      headers
  )
endif()

#-----------------------------------------------------------------------------
# Add Target(s) to CMake Install
#-----------------------------------------------------------------------------
install(
  TARGETS
    mercury
  EXPORT
    ${MERCURY_EXPORTED_TARGETS}
  LIBRARY DESTINATION ${MERCURY_INSTALL_LIB_DIR}
  ARCHIVE DESTINATION ${MERCURY_INSTALL_LIB_DIR}
  PUBLIC_HEADER DESTINATION ${MERCURY_INSTALL_INCLUDE_DIR}
  RUNTIME DESTINATION ${MERCURY_INSTALL_BIN_DIR}
)

#-----------------------------------------------------------------------------
# Add Target(s) to CMake Install for import into other projects
#-----------------------------------------------------------------------------
install(
  EXPORT
    ${MERCURY_EXPORTED_TARGETS}
  DESTINATION
    ${MERCURY_INSTALL_DATA_DIR}/cmake/${MERCURY_PACKAGE}
  FILE
    ${MERCURY_EXPORTED_TARGETS}.cmake
)

#-----------------------------------------------------------------------------
# Export all exported targets to the build tree for use by parent project
#-----------------------------------------------------------------------------
if(NOT MERCURY_EXTERNALLY_CONFIGURED)
  export(
    TARGETS
      ${MERCURY_EXPORTED_LIBS}
    FILE
      ${MERCURY_EXPORTED_TARGETS}.cmake
  )
endif()

#------------------------------------------------------------------------------
# Set variables for parent scope
#------------------------------------------------------------------------------
set(NA_PLUGINS ${NA_PLUGINS} PARENT_SCOPE)

#-----------------------------------------------------------------------------
# For automake compatibility, also provide a pkgconfig file
#-----------------------------------------------------------------------------
if(NOT WIN32)
  # Retrieve Mercury library
  mercury_get_pc_lib_name(MERCURY_PC_LIBRARY mercury)

  # Pkg dependencies
  string(REPLACE ";" " "
         MERCURY_PC_INT_PKG_DEPENDENCIES "${MERCURY_INT_PKG_DEPENDENCIES}")

  # Mercury internal library dependencies
  mercury_get_pc_lib_deps(MERCURY_PC_INT_LIB_DEPENDENCIES "${MERCURY_INT_LIB_DEPENDENCIES}")

  # Mercury external library dependencies
  mercury_get_pc_lib_deps(MERCURY_PC_LIB_DEPENDENCIES "${MERCURY_EXT_LIB_DEPENDENCIES}")

  # External include dependencies
  if(MERCURY_EXT_INCLUDE_DEPENDENCIES)
    list(REMOVE_DUPLICATES MERCURY_EXT_INCLUDE_DEPENDENCIES)
    mercury_get_pc_inc_deps(MERCURY_PC_INCLUDE_DEPENDENCIES "${MERCURY_EXT_INCLUDE_DEPENDENCIES}")
  endif()

  # Configure pkg-config file
  configure_file(
    ${MERCURY_SOURCE_DIR}/CMake/${MERCURY_PACKAGE}.pc.in
    ${MERCURY_BINARY_DIR}/CMakeFiles/${MERCURY_PACKAGE}.pc @ONLY
  )

  # Install pkg-config file
  install(
    FILES
      ${MERCURY_BINARY_DIR}/CMakeFiles/${MERCURY_PACKAGE}.pc
    DESTINATION
      ${MERCURY_INSTALL_LIB_DIR}/pkgconfig
  )
endif()
